/**
 * 
 */
package utility.io;

import handwritten.character.CharacterCollection;
import handwritten.character.CharacterCollectionManager;
import handwritten.character.HandWritten;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Set;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import auth.User;

/**
 * @author Louis
 * 
 */
public class XMLHWCharacterIO extends HWCharacterIO {

	String extension = ".xml";
	//dir where the information are stored
	String infoDir      = "information";
	
	/**
	 * @param path
	 */
	XMLHWCharacterIO(String path) {
		super(path);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see utility.io.HWCharacterIO#saveCollection(textRecognition.character.
	 * CharacterCollection, java.lang.String)
	 */
	@Override
	public void saveCollections(User name) throws IOException {

		ArrayList<CharacterCollection<?>> collections = CharacterCollectionManager
				.getInstance().getCollections(name);
		
		Path p;
		Path info;
		
		
		
		try{
		for (CharacterCollection<?> collection : collections) {

			JAXBContext context = JAXBContext.newInstance(collection.getType());
			Marshaller u = context.createMarshaller();

			Enumeration<String> keys = collection.keys();

			while (keys.hasMoreElements()) {
				String key = keys.nextElement();
				
				// path utile letter name
				p = Paths
						.get(this.getPath().toString(), name.getUsername(),collection.getCollecType(),
								collection.getType().getName(), idToName(key));
				//information directory
				info =  Paths
						.get(this.getPath().toString(), name.getUsername(),collection.getCollecType(),
								collection.getType().getName(), infoDir);
				
				String folderPath = p.toString();

				Files.createDirectories(p);
				//generate the information files
				Files.createDirectories(info);
				info = Paths.get(info.toString(), idToName(key)+".txt");
				PrintWriter writer = new PrintWriter(new FileWriter(info.toString()));
				
				for (int i = 0; i < collection.size(key); i++) {
					//save letter
					u.marshal(collection.get(key, i),
							Paths.get(folderPath,Integer.toString(collection.get(key, i).hashCode())+extension).toFile());
					
					//write the information file
					writer.println("-----------------------------------------------------------------------------");
					writer.println(collection.get(key, i).hashCode());
					writer.println();
					writer.println(collection.get(key, i).writeRepresentation());
				}
				//close the stream
				writer.close();
			}

		}
		}catch(JAXBException e){
			e.printStackTrace();
			throw new IOException("Error while saving collections for : "+name.getUsername());
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see utility.io.HWCharacterIO#loadCollection(java.lang.String)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void loadCollections(User name) throws IOException {

		
		DirectoryStream<Path> collecTypes = Files.newDirectoryStream(Paths.get(this.getPath().toString(), name.getUsername()));
		DirectoryStream<Path> pTypes = null;
		CharacterCollection<HandWritten> collection;
		Class<? extends HandWritten> type;
		
		String filestype;
		
		for(Path collecType : collecTypes)
		{
			pTypes = Files.newDirectoryStream(collecType);
			for (Path pType : pTypes) 
			{
				System.out.println("try to load " + pType.getFileName().toString());
				
				try {
					// We try to load only if the folder correspond to an HandWritten sub-class
					if(HandWritten.class.isAssignableFrom(Class.forName(pType.getFileName().toString()))){
						JAXBContext context = JAXBContext.newInstance(Class.forName(pType.getFileName().toString()));
						//These two casts are unchecked but is sage because we check that type is assignable
						type = (Class<? extends HandWritten>) Class.forName(pType.getFileName().toString());
						collection = (CharacterCollection<HandWritten>) CharacterCollectionManager.getInstance().getCollection(name,collecType.getFileName().toString(),type);
						
						Unmarshaller u = context.createUnmarshaller();
		
						DirectoryStream<Path> dir = Files.newDirectoryStream(pType);
		
						for (Path p : dir) {
							if(!p.getFileName().equals("information"))
							{
								DirectoryStream<Path> letters = Files.newDirectoryStream(p);
								for (Path letter : letters) {
									if (letter.toFile().isFile()) {
										filestype = Files.probeContentType(letter);
										if(filestype.equals("application/xml")||filestype.equals("text/xml"))
										{
											System.out.println("loading " +letter.toString() );
											collection.addSample((HandWritten) u.unmarshal(letter.toFile()));
										}
									}
								}
							}
						}
					}
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
					throw new IOException("Error while reading collections for : "+name.getUsername());
				} catch (JAXBException e) {
					e.printStackTrace();
					throw new IOException("Error while reading collections for : "+name.getUsername());
				}	
			}
		}

	}

	/*
	 * (non-Javadoc)
	 * http://docs.oracle.com/javase/7/docs/api/java/nio/package-summary.html
	 * @see utility.io.HWCharacterIO#getFormat()
	 */
	@Override
	public String getFormat() {
		return "XML";
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see utility.io.HWCharacterIO#loadDataBase(java.lang.String)
	 */
	@Override
	public void loadDataBase() throws IOException {
		DirectoryStream<Path> pUsers = Files.newDirectoryStream(Paths.get(this.getPath().toString()));
		for(Path p : pUsers){
			loadCollections(new User(p.getFileName().toString()));
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see utility.io.HWCharacterIO#saveDataBase(textRecognition.character.
	 * CharacterCollectionManager, java.lang.String)
	 */
	@Override
	public void saveDataBase() throws IOException {
		Set<User> users = CharacterCollectionManager.getInstance().getUsers();
		for(User user : users)
			saveCollections(user);
	}
	

}
